#include "stdafx.h"

/* abstract bullet classes ***********************************************************
** Bullet
** Hero Bullet
** EnemyBullet
*/

Bullet::Bullet(const std::wstring & name, int vx, int vy, int x, int y, const std::wstring & sname, int lifespan, int rotatespeed)
{
	this->vx = vx;
	this->vy = vy;
	this->x = x;
	this->y = y;
	//this->picname = name;
	this->rotatespeed = rotatespeed;
	this->livetime = lifespan;
	strategy = BStrategyMgr::getInstance()->get(sname);

	image = ImageMgr::getInstance()->getImageFromName(L"img\\" + name + L".png");
	width = image->GetWidth();
	height = image->GetHeight();
}

Bullet::Bullet(const tagBullet & bullet, int x, int y, int vx, int vy)
{
	this->vx = vx;
	this->vy = vy;
	this->x = x;
	this->y = y;
	rotatespeed = bullet.rotatespeed;
	livetime = bullet.lifespan;
	strategy = BStrategyMgr::getInstance()->get(bullet.sname);

	for (int i = 0; i < 4; i++)
	{
		damage[i] = bullet.damage[i];
	}

	image = ImageMgr::getInstance()->getImageFromName(L"img\\" + bullet.picname + L".png");
	width = image->GetWidth();
	height = image->GetHeight();
}

Bullet::~Bullet()
{
}

void Bullet::setPowerGrade(int grade)
{
	power = grade;
}

void Bullet::update(double dtime)
{
	angle += rotatespeed*dtime;
	while (angle >= 360)
	{
		angle -= 360;
	}
	x += dtime*vx;
	y += dtime*vy;

	time += dtime;

	//Rect newPos;

	//newPos = strategy->idea(Game::getInstance()->getHero()->getPoint(), { (int)x,(int)y }, dtime, vx, vy, livetime);
	/*x = newPos.X;
	y = newPos.Y;
	vx = newPos.Width;
	vy = newPos.Height;*/
	strategy->idea(x, y, dtime, time, vx, vy);
}

void Bullet::draw(Graphics * graphics)
{
	graphics->RotateTransform(angle, MatrixOrder::MatrixOrderAppend);
	graphics->TranslateTransform(x, y, MatrixOrder::MatrixOrderAppend);
	graphics->DrawImage(image, (REAL)(-width / 2.0), (REAL)(-height / 2.0));
	graphics->ResetTransform();
}

HeroBullet::HeroBullet(const std::wstring & name, int vx, int vy, int x, int y, const std::wstring & sname, int lifespan, int rotatespeed)
	:Bullet(name, vx, vy, x, y, sname, lifespan, rotatespeed)
{
}

HeroBullet::HeroBullet(const tagBullet & bullet, int x, int y, int vx, int vy)
	: Bullet(bullet, x, y, vx, vy)
{
}

HeroBullet::~HeroBullet()
{
}

bool HeroBullet::collisiondetect()
{
	bool ans = false;

	int mapx = floor((x - LEFTMAP) / GRIDSIZE);
	int mapy = floor((y - TOPMAP) / GRIDSIZE);

	EnemyTank * collide = EnemyMgr::getInstance()->collide({ (int)x, (int)y });
	if (collide)																		//collide with an enemy
	{
		//collide->bleed(power);
		ans = true;
	}

	if (Map::getInstance()->getWall()->collide({ (int)x,(int)y }))						//collide with a wall
	{
		//Map::getInstance()->getWall()->crash({ { mapx,mapy } });
		ans = true;
	}

	if (Map::getInstance()->getSteel()->collide({ (int)x,(int)y }))						//collide with a steel
	{
		ans = true;
	}

	return ans;
}

EnemyBullet::EnemyBullet(const std::wstring & name, int vx, int vy, int x, int y, const std::wstring & sname, int lifespan, int rotatespeed)
	:Bullet(name, vx, vy, x, y, sname, lifespan, rotatespeed)
{
}

EnemyBullet::EnemyBullet(const tagBullet & bullet, int x, int y, int vx, int vy)
	: Bullet(bullet, x, y, vx, vy)
{
}

EnemyBullet::~EnemyBullet()
{
}

bool EnemyBullet::collisiondetect()
{
	bool ans = false;

	int mapx = floor((x - LEFTMAP) / GRIDSIZE);
	int mapy = floor((y - TOPMAP) / GRIDSIZE);

	HeroTank * hero = Game::getInstance()->getHero();
	if (hero->collide({ (int)x,(int)y }))												//collide with the hero
	{
		//hero->bleed(power);
		ans = true;
	}

	if (Map::getInstance()->getWall()->collide({ (int)x,(int)y }))						//collide with a wall
	{
		//Map::getInstance()->getWall()->crash({ { mapx,mapy } });
		ans = true;
	}

	if (Map::getInstance()->getSteel()->collide({ (int)x,(int)y }))						//collide with a steel
	{
		ans = true;
	}

	if (time >= livetime)
	{
		ans = true;
	}

	return ans;
}

/****************************************************************************************************************
*****************************************************************************************************************
****************************************************************************************************************/

DotBullet::DotBullet(const std::wstring & name, int vx, int vy, int x, int y, const std::wstring & sname, int lifespan, int rotatespeed)
	:HeroBullet(name, vx, vy, x, y, sname, lifespan, rotatespeed)
{
	/*damage[0] = 1;
	damage[1] = 2;
	damage[2] = 3;
	damage[3] = 4;*/
}

DotBullet::DotBullet(const tagBullet & bullet, int x, int y, int vx, int vy)
	:HeroBullet(bullet, x, y, vx, vy)
{
}

DotBullet::~DotBullet()
{
	//hit();
}

void DotBullet::blast()
{
	AnimationMgr::getInstance()->create(L"blast1", 8, 0.2, x, y);
}

void DotBullet::hit()
{
	int cx = floor((x - LEFTMAP) / GRIDSIZE);
	int cy = floor((y - TOPMAP) / GRIDSIZE);

	Map::getInstance()->getWall()->crash({ {cx,cy} });

	EnemyTank * collide = EnemyMgr::getInstance()->collide({ (int)x,(int)y });
	if (collide)
	{
		collide->bleed(getDamage());
	}
}

Missile::Missile(const std::wstring & name, int vx, int vy, int x, int y, const std::wstring & sname, int lifespan, int rotatespeed)
	:HeroBullet(name, vx, vy, x, y, sname, lifespan, rotatespeed)
{
	/*damage[0] = 2;
	damage[1] = 3;
	damage[2] = 5;
	damage[3] = 8;*/
}

Missile::Missile(const tagBullet & bullet, int x, int y, int vx, int vy)
	:HeroBullet(bullet, x, y, vx, vy)
{
}

Missile::~Missile()
{
	//hit();
}

void Missile::blast()
{
	AnimationMgr::getInstance()->create(L"blast2", 7, 0.9, x, y);
}

void Missile::hit()
{
	static int u[] = { 0,1,1,1,0,-1,-1,-1,0 };
	static int v[] = { -1,-1,0,1,1,1,0,-1,0 };

	EnemyTank * collide = nullptr;

	int cx = floor((x - LEFTMAP) / GRIDSIZE);
	int cy = floor((y - TOPMAP) / GRIDSIZE);

	for (int i = 0; i < 9; i++)
	{
		int tx = cx + u[i];
		int ty = cy + v[i];

		if (tx >= 0 && tx < XMAP && ty >= 0 && ty <= YMAP)
		{
			Map::getInstance()->getWall()->crash({ { cx + u[i],cy + v[i] } });
		}
		
		collide = EnemyMgr::getInstance()->collide({ (int)x + u[i] * 60,(int)y + v[i] * 60 });
		if (collide)
		{
			collide->bleed(getDamage());
		}
	}
}

EDotBullet::EDotBullet(const std::wstring & name, int vx, int vy, int x, int y, const std::wstring & sname, int lifespan, int rotatespeed) 
	:EnemyBullet(name, vx, vy, x, y, sname, lifespan, rotatespeed)
{
	/*damage[0] = 1;
	damage[1] = 2;
	damage[2] = 3;
	damage[3] = 4;*/
}

EDotBullet::EDotBullet(const tagBullet & bullet, int x, int y, int vx, int vy)
	:EnemyBullet(bullet, x, y, vx, vy)
{
}

EDotBullet::~EDotBullet()
{
	//hit();
}

void EDotBullet::hit()
{
	int cx = floor((x - LEFTMAP) / GRIDSIZE);
	int cy = floor((y - TOPMAP) / GRIDSIZE);

	Map::getInstance()->getWall()->crash({ { cx,cy } });

	HeroTank * hero = Game::getInstance()->getHero();
	if (hero->collide({ (int)x,(int)y }))
	{
		hero->bleed(getDamage());
	}
}

void EDotBullet::blast()
{
	AnimationMgr::getInstance()->create(L"blast4", 6, 0.2, (int)x, (int)y);
}